<template>
  <div class="image-protector">
    <h3>图片保护处理组件（支持网络链接）</h3>

    <!-- 输入区域：支持网络链接和本地文件 -->
    <div class="input-area">
      <div class="network-input">
        <input 
          type="text" 
          v-model="networkImageUrl" 
          placeholder="输入网络图片URL（如：https://xxx.com/img.jpg）"
          class="url-input"
        />
        <button @click="handleNetworkImage">网络图片处理</button>
      </div>
      
      <div class="local-input">
        <input type="file" accept="image/*" @change="handleLocalImage" class="file-input" />
        <span class="local-tip">或选择本地图片文件</span>
      </div>
    </div>

    <!-- 处理后的图片展示（Canvas渲染） -->
    <div class="image-container" v-if="isProcessed">
      <h4>处理后图片（禁止直接查看原图和下载）</h4>
      <!-- Canvas渲染层（核心保护） -->
      <canvas 
        :width="canvasWidth" 
        :height="canvasHeight" 
        ref="imageCanvas"
        @contextmenu.prevent="handleRightClick"  <!-- 禁用右键 -->
        @dragstart.prevent  <!-- 禁用拖拽 -->
        class="protected-canvas"
      ></canvas>

      <!-- 隐藏的原始图片（仅用于中转二进制数据） -->
      <img 
        :src="tempImageUrl" 
        ref="hiddenImg" 
        style="display: none"
        @load="drawToCanvas"
      >
    </div>

    <!-- 状态提示 -->
    <div class="status" v-if="statusMessage">
      {{ statusMessage }}
    </div>
  </div>
</template>

<script setup>
import { ref, onUnmounted } from 'vue';

// 网络图片URL输入
const networkImageUrl = ref('');
// 临时图片链接（二进制转换用）
const tempImageUrl = ref('');
// Canvas尺寸
const canvasWidth = ref(0);
const canvasHeight = ref(0);
// 状态信息
const statusMessage = ref('');
// 处理状态标记
const isProcessed = ref(false);
// 引用
const imageCanvas = ref(null);
const hiddenImg = ref(null);
// 存储已创建的Blob链接（用于卸载时释放）
const createdBlobUrls = ref([]);

/**
 * 处理网络图片：通过Fetch获取二进制数据
 */
const handleNetworkImage = async () => {
  if (!networkImageUrl.value) {
    statusMessage.value = '请输入网络图片URL';
    return;
  }

  try {
    statusMessage.value = '正在获取网络图片...';
    // 1. 验证URL格式
    if (!isValidUrl(networkImageUrl.value)) {
      statusMessage.value = '请输入有效的URL（以http/https开头）';
      return;
    }

    // 2. 发起请求获取二进制数据（Blob）
    const response = await fetch(networkImageUrl.value);
    if (!response.ok) throw new Error(`请求失败，状态码：${response.status}`);

    // 3. 转换为Blob并生成临时链接
    const blob = await response.blob();
    const blobUrl = URL.createObjectURL(blob);
    createdBlobUrls.value.push(blobUrl); // 记录需释放的链接

    // 4. 触发Canvas绘制
    tempImageUrl.value = blobUrl;
    isProcessed.value = true;
    statusMessage.value = '网络图片获取成功，处理中...';
  } catch (err) {
    statusMessage.value = `网络图片处理失败：${err.message}（可能跨域限制）`;
    isProcessed.value = false;
  }
};

/**
 * 处理本地图片：通过FileReader获取二进制数据
 */
const handleLocalImage = (e) => {
  const file = e.target.files[0];
  if (!file) return;

  // 验证图片类型
  if (!file.type.startsWith('image/')) {
    statusMessage.value = '请选择图片文件（JPG/PNG等）';
    return;
  }

  try {
    // 生成Blob链接
    const blobUrl = URL.createObjectURL(file);
    createdBlobUrls.value.push(blobUrl);
    
    // 触发Canvas绘制
    tempImageUrl.value = blobUrl;
    isProcessed.value = true;
    statusMessage.value = '本地图片加载成功，处理中...';
  } catch (err) {
    statusMessage.value = `本地图片处理失败：${err.message}`;
    isProcessed.value = false;
  }

  // 清空输入，允许重复选择
  e.target.value = '';
};

/**
 * 将图片二进制数据通过Canvas重新绘制（核心保护逻辑）
 */
const drawToCanvas = () => {
  const img = hiddenImg.value;
  const canvas = imageCanvas.value;
  if (!img || !canvas) return;

  try {
    // 设置Canvas尺寸与原图一致
    canvasWidth.value = img.naturalWidth;
    canvasHeight.value = img.naturalHeight;
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;

    // 绘制图片到Canvas
    const ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);

    statusMessage.value = '图片处理完成（已禁止直接查看和下载原图）';
  } catch (err) {
    statusMessage.value = `Canvas绘制失败：${err.message}`;
    isProcessed.value = false;
  }
};

/**
 * 禁用右键菜单提示
 */
const handleRightClick = () => {
  statusMessage.value = '禁止右键下载原图';
  setTimeout(() => {
    if (statusMessage.value.includes('禁止右键')) {
      statusMessage.value = '图片处理完成（已禁止直接查看和下载原图）';
    }
  }, 2000);
};

/**
 * URL格式验证
 */
const isValidUrl = (url) => {
  try {
    new URL(url);
    return url.startsWith('http://') || url.startsWith('https://');
  } catch {
    return false;
  }
};

/**
 * 组件卸载时释放所有Blob链接（避免内存泄漏）
 */
onUnmounted(() => {
  createdBlobUrls.value.forEach(url => {
    URL.revokeObjectURL(url);
  });
  createdBlobUrls.value = [];
});
</script>

<style scoped>
.image-protector {
  max-width: 800px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
}

.input-area {
  margin: 20px 0;
  padding: 15px;
  background: #f5f5f5;
  border-radius: 4px;
}

.network-input {
  margin-bottom: 15px;
  display: flex;
  gap: 10px;
  align-items: center;
}

.url-input {
  flex: 1;
  padding: 8px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.local-input {
  display: flex;
  align-items: center;
  gap: 10px;
}

.file-input {
  padding: 5px;
}

.local-tip {
  color: #666;
  font-size: 14px;
}

button {
  padding: 8px 16px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
}

button:hover {
  background-color: #359e6d;
}

.image-container {
  margin: 20px 0;
  padding: 15px;
  background: #fafafa;
  border-radius: 4px;
}

.protected-canvas {
  max-width: 100%;
  border: 1px dashed #ccc;
  cursor: not-allowed;
  background-color: #f9f9f9;
}

.status {
  margin: 10px 0;
  padding: 10px;
  border-radius: 4px;
  color: #333;
  background: #f0f9ff;
  min-height: 24px;
}
</style>